/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/tree.h>

#include "parse_alarms.h"

//-----------------------------------------------------------------------------
// загрузить комментарии из файла
//-----------------------------------------------------------------------------
static void parse_comment (alarms_t* alarms, xmlDoc* doc, xmlNode* node)
{
	comment_t*	comment;
	int			id;
	
	id = atoi (xmlGetProp (node, "id"));

	alarms->n_comment = max (alarms->n_comment, id+1);
	alarms->comment = realloc (alarms->comment, alarms->n_comment * sizeof (comment_t));
	if (alarms->comment == NULL) {
		fprintf (stderr, "error realloc () in parse_comment\n");
		exit (EXIT_FAILURE);
	}
	comment = &alarms->comment [id];
	memset (comment, 0, sizeof (comment_t));
	comment->id = id;
	comment->txt = strdup (xmlNodeListGetString (doc, node->xmlChildrenNode, 1));
}

//-----------------------------------------------------------------------------
// загрузить список комментариев из файла
//-----------------------------------------------------------------------------
static void parse_comments (alarms_t* alarms, xmlDoc* doc, xmlNode* node)
{
	xmlNodePtr 	cur = node->xmlChildrenNode;
	while (cur != NULL) {
		if (!xmlStrcmp (cur->name, (const xmlChar *) "comment")) {
			parse_comment (alarms, doc, cur);
		}
		cur = cur->next;
	}		
}

//-----------------------------------------------------------------------------
// загрузить данные о сообщении из файла
//-----------------------------------------------------------------------------
static void parse_alarm (alarms_t* alarms, xmlDoc* doc, xmlNode* node)
{
	xmlNodePtr 	cur = node->xmlChildrenNode;
	alarm_t*	alarm;
	
	alarms->n_alarm ++;
	alarms->alarm = realloc (alarms->alarm, alarms->n_alarm * sizeof (alarm_t));
	if (alarms->alarm == NULL) {
		fprintf (stderr, "error realloc () in parse_alarm\n");
		exit (EXIT_FAILURE);
	}
	alarm = &alarms->alarm [alarms->n_alarm -1];
	memset (alarm, 0, sizeof (alarm_t));

	alarm->name = strdup (xmlGetProp (node, "name"));
	alarm->priority = atoi (xmlGetProp (node, "priority"));
	alarm->addr = atoi (xmlGetProp (node, "addr"));
	alarm->bitnum = atoi (xmlGetProp (node, "bitnum"));
	alarm->front = atoi (xmlGetProp (node, "front"));
	alarm->comment_id = atoi (xmlGetProp (node, "comment_id"));

	while (cur != NULL) {
		if (!xmlStrcmp (cur->name, (const xmlChar *) "msg")) {
			alarm->msg = strdup (xmlNodeListGetString (doc, cur->xmlChildrenNode, 1));
		}
		cur = cur->next;
	}		
}

//-----------------------------------------------------------------------------
// загрузить сообщения для устройства из файла
//-----------------------------------------------------------------------------
static void parse_device (alarms_t* alarms, xmlDoc* doc, xmlNode* node)
{
	xmlNodePtr 	cur = node->xmlChildrenNode;
	
	alarms->dev_name = strdup (xmlGetProp (node, "name"));

	while (cur != NULL) {
		if (!xmlStrcmp (cur->name, (const xmlChar *) "alarm")) {
	       	parse_alarm (alarms, doc, cur);
		}
		cur = cur->next;
	}		
}

//-----------------------------------------------------------------------------
// загрузить сообщения из файла
//-----------------------------------------------------------------------------
alarms_t* parse_alarms (const char* filename)
{
	xmlDoc* 	doc;
    xmlNode* 	node;
    xmlNode* 	cur;
    alarms_t*	alarms;
	
	alarms = malloc (sizeof (alarms_t));
	if (alarms == NULL) {
		fprintf (stderr, "error malloc () in parse_alarms\n");	
        exit (EXIT_FAILURE);
	}
	memset (alarms, 0, sizeof (alarms_t));
	
	doc = xmlParseFile (filename);
    if (doc == NULL) {
        fprintf (stderr, "error: could not parse alarms file (%s)\n", filename);
        exit (EXIT_FAILURE);
    }

    node = xmlDocGetRootElement (doc);
	if (xmlStrcmp (node->name, (const xmlChar *) "alarms")) {
        fprintf (stderr, "error: wrong format of alarms file (%s)\n", filename);
        exit (EXIT_FAILURE);
	}
	
    cur = node->xmlChildrenNode;
    while (cur != NULL) {
       	if (!xmlStrcmp (cur->name, (const xmlChar *) "device")) {
	       	parse_device (alarms, doc, cur);
	    }
       	if (!xmlStrcmp (cur->name, (const xmlChar *) "comments")) {
	       	parse_comments (alarms, doc, cur);
	    }
       	cur = cur->next;
    }
    
    xmlFreeDoc (doc);
    xmlCleanupParser ();
    
    return alarms;
}